﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Dynamic;

namespace NougakudoSetupTool
{
    static class ZipUtility
    {
        const int FOR_SILENT = 0x0004;
        const int FOR_NOCONFIRMATION = 0x0010;
        const int FOR_NORERROR_UI = 0x0400;
        const int FOR_NOCONFIRMMKDIR = 0x0200;
        const int FOR_NO_UI = FOR_SILENT | FOR_NOCONFIRMATION | FOR_NORERROR_UI | FOR_NOCONFIRMMKDIR;
        
        /// <summary>
        /// Extract zip archive file.
        /// If zip include a top folder name as zip file name, extract the include items only.
        /// Else extract all items.
        /// </summary>
        /// <param name="zipFileName">Zip file name of full path </param>
        /// <param name="folderName">Copy folder of full path</param>
        /// <returns></returns>
        static public Tuple<bool,string> UnZip(string zipFileName, string folderName)
        {
            if (!File.Exists(zipFileName)) return new Tuple<bool,string>(false, zipFileName + " not exsist.");

            CheckDestinationFolder(folderName);

            try
            {
                dynamic shellApp = Activator.CreateInstance(Type.GetTypeFromProgID("Shell.Application"));
                dynamic sourceFolder = shellApp.NameSpace(zipFileName);
                dynamic destinationFolder = shellApp.NameSpace(folderName);

                dynamic filter = GetRootFolder(sourceFolder, zipFileName);
                if (filter == null)
                {
                    //destinationFolder.CopyHere(sourceFolder.Items, FOR_NOCONFIRMATION);
                    destinationFolder.CopyHere(sourceFolder.Items, FOR_NO_UI);
                }
                else
                {
                    var folder = filter.GetFolder();    // cast FolderItem to Folder
                    //destinationFolder.CopyHere(folder.Items, FOR_NOCONFIRMATION);
                    destinationFolder.CopyHere(folder.Items, FOR_NO_UI);
                }
            }
            catch (Exception e)
            {

                return new Tuple<bool,string>(false, e.Message);
            }

            return new Tuple<bool,string>(true, "");
        }



        static void CheckDestinationFolder(string folderName)
        {
            if (!Directory.Exists(folderName))
                Directory.CreateDirectory(folderName);
            else
            {
                Directory.Delete(folderName, true);
                Directory.CreateDirectory(folderName);
            }
        }

        static dynamic GetRootFolder(dynamic zipFolder, string zipFileName)
        {
            var folder = Path.GetFileNameWithoutExtension(zipFileName);
            foreach (var item in zipFolder.Items)
            {
                try
                {
                    var itemFolder = item.GetFolder();
                    if (itemFolder != null && itemFolder.Name == folder)
                        return item;
                }
                catch (Exception e)
                {
                }
            }
            return null;
        }


        /// <summary>
        /// Create zip archive file.
        /// If zip archive file exsists, add item.
        /// </summary>
        /// <param name="zipFileName">Zip file name of full path</param>
        /// <param name="item">file or directory</param>
        /// <returns></returns>
        static public Tuple<bool,string> CreateZip(string zipFileName, string item)
        {
            var ret = CreateZip(zipFileName, new string[] { item });
            return ret;
        }

        /// <summary>
        /// Create zip archive file.
        /// If zip archive file exsists, add item.
        /// </summary>
        /// <param name="zipFileName">Zip file name of full path</param>
        /// <param name="items">item array. item is file or directory</param>
        /// <returns></returns>
        static public Tuple<bool, string> CreateZip(string zipFileName, string[] items)
        {
            foreach (var item in items)
            {
                if (!ExistsItem(item)) return new Tuple<bool,string>(false, item + " not exsist.");

                CreateZipFile(zipFileName);

                try
                {
                    dynamic shellApp = Activator.CreateInstance(Type.GetTypeFromProgID("Shell.Application"));
                    dynamic zipFolder = shellApp.NameSpace(zipFileName);
                    if (File.Exists(item))  // file case.
                        zipFolder.CopyHere(item, FOR_NO_UI);
                    else  // folder case
                    {
                        dynamic target = shellApp.NameSpace(item);
                        zipFolder.CopyHere(target, FOR_NO_UI);
                    }
                }
                catch (Exception e)
                {
                    return new Tuple<bool, string>(false, e.Message);
                }
            }
            return new Tuple<bool,string>(true, "");
        }

        static void CreateZipFile(string zipFileName)
        {
            var zip = File.Create(zipFileName);
            var sw = new StreamWriter(zip);
            zip.Close();
        }

        static bool ExistsItem(string item)
        {
            if (File.Exists(item))
                return true;
            if (Directory.Exists(item))
                return true;
            return false;
        }
    }
}
